/*
 * FileUtil.java
 */
package com.xjj.sso.server.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;

public class FileUtil {

  static final int BUFFER = 2048;

  protected static final Logger log = Logger.getLogger(FileUtil.class);

  public static char[] hexChar = { '0', '1', '2', '3', '4', '5', '6', '7', '8',
      '9', 'a', 'b', 'c', 'd', 'e', 'f' };

  /**
   * 
   * 功能描述：获取文件的MD5值
   * 
   * @author 
   * @version
   * @date: Nov 30, 2007
   * 
   * @param fileName
   * @return
   * @throws Exception
   */
  public static String getHashCode(String fileName) throws Exception {
    InputStream fis;
    fis = new FileInputStream(fileName);
    byte[] buffer = new byte[1024 * 1024];
    MessageDigest md5 = MessageDigest.getInstance("MD5");
    int numRead = 0;
    while ((numRead = fis.read(buffer)) > 0) {
      md5.update(buffer, 0, numRead);
    }
    fis.close();
    return toHexString(md5.digest());
  }

  /**
   * 
   * 功能描述：将二进制转换为hex字符串
   * 
   * @author 
   * @version
   * @date: Nov 30, 2007
   * 
   * @param b
   * @return
   */
  public static String toHexString(byte[] b) {
    StringBuilder sb = new StringBuilder(b.length * 2);
    for (int i = 0; i < b.length; i++) {
      sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
      sb.append(hexChar[b[i] & 0x0f]);
    }
    return sb.toString();
  }

  /**
   * 压缩
   * 
   * @author  Created on 2007-8-10 上午11:33:05
   * 
   * @param compress
   *            压缩后的文件名称
   * @param compressed
   *            被压缩的路径或文件
   * @return 压缩是否成功
   */
  public static boolean compress(String compress, String compressed) {
    try {

      ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(new File(
          compress)));

      File f = new File(compressed);
      pCompress(zout, f, "");
      zout.close();
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  /**
   * 压缩
   * 
   * @author  Created on 2007-8-10 下午06:27:35
   * 
   * @param out
   *            输出流
   * @param f
   *            要压缩的文件
   * @param pName
   *            上级目录
   * @throws FileNotFoundException
   * @throws IOException
   */
  public static void pCompress(ZipOutputStream out, File f, String pName)
      throws FileNotFoundException, IOException {
    BufferedInputStream origin;
    byte data[] = new byte[BUFFER];
    if (f.isFile()) {
      FileInputStream fi = new FileInputStream(f);
      origin = new BufferedInputStream(fi, BUFFER);

      ZipEntry entry = new ZipEntry(pName + f.getName());
      out.putNextEntry(entry);
      int count;
      while ((count = origin.read(data, 0, BUFFER)) != -1) {
        out.write(data, 0, count);
      }
      origin.close();
      out.closeEntry();
    } else if (f.isDirectory()) {
      File files[] = f.listFiles();
      for (int i = 0; i < files.length; i++) {
        pCompress(out, files[i], pName + f.getName() + File.separator);
      }
    }
  }

  /**
   * 压缩
   * 
   * @author  Created on 2007-8-10 上午11:33:05
   * 
   * @param compress
   *            压缩后的文件名称
   * @param compressed
   *            被压缩的路径或文件
   * @return 压缩是否成功
   */
  public static boolean compressNew(String compress, String compressed) {
    try {

      ZipOutputStream zout = new ZipOutputStream(new FileOutputStream(new File(
          compress)));

      File f = new File(compressed);
      pCompressNew(zout, f, "", true);
      zout.close();
    } catch (Exception e) {
      e.printStackTrace();
      return false;
    }
    return true;
  }

  /**
   * 压缩
   * 
   * @author  Created on 2007-8-10 下午06:27:35
   * 
   * @param out
   *            输出流
   * @param f
   *            要压缩的文件
   * @param pName
   *            上级目录
   * @throws FileNotFoundException
   * @throws IOException
   */
  private static void pCompressNew(ZipOutputStream out, File f, String pName,
      boolean isParent) throws FileNotFoundException, IOException {
    BufferedInputStream origin;
    byte data[] = new byte[BUFFER];
    if (f.isFile()) {
      FileInputStream fi = new FileInputStream(f);
      origin = new BufferedInputStream(fi, BUFFER);

      ZipEntry entry = new ZipEntry(pName + f.getName());
      out.putNextEntry(entry);
      int count;
      while ((count = origin.read(data, 0, BUFFER)) != -1) {
        out.write(data, 0, count);
      }
      origin.close();
      out.closeEntry();
    } else if (f.isDirectory()) {
      File files[] = f.listFiles();
      if (isParent) {
        for (int i = 0; i < files.length; i++) {
          pCompressNew(out, files[i], "", false);
        }
      } else {
        for (int i = 0; i < files.length; i++) {
          pCompressNew(out, files[i], pName + f.getName() + File.separator,
              false);
        }
      }

    }
  }


  /**
   * 文件初始化方法（创建文件夹或删除文件夹下的文件）
   * 
   * @param filePath
   * @throws IOException
   */
  public static void fileInitialize(String filePath) throws IOException {
    File file = new File(filePath);
    if (!file.exists()) {
      // 文件不存在，创建
      file.mkdirs();
    } else {
      // 文件存在删除
      deleteDirectory(file);
    }
  }

  /**
   * 如果文件夹不存在，创建
   * 
   * @param filePath
   * @throws IOException
   */
  public static void createDirectory(String filePath) throws IOException {
    File file = new File(filePath);
    if (!file.exists()) {
      // 文件不存在，创建
      file.mkdirs();
    }
  }
  /**
   * 提供删除目录和文件
   * 
   * @param dir
   * @throws IOException
   */
  public static void deleteDirectory(File dir) throws IOException {
    if ((dir == null) || !dir.isDirectory()) {
    	return ;
    }
    File[] entries = dir.listFiles();
    int sz = entries.length;
    for (int i = 0; i < sz; i++) {
      if (entries[i].isDirectory()) {
        deleteDirectory(entries[i]);
      } else {
        try {
          entries[i].delete();
        } catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    }
  }

  /**
   * 删除指定文件夹
   * 
   * @param forder
   * @throws IOException
   */
  public static void deleteFilesAndForder(File forder) throws IOException {
    if (forder.isDirectory()) {
      File[] file = forder.listFiles();
      for (int i = 0; i < file.length; i++) {
        deleteFilesAndForder(file[i]);
      }
    } else {
      forder.delete();
    }
    forder.delete();
  }

	/**
	 * 提供删除目录和文件
	 * 
	 * @param dir
	 * @throws IOException
	 */
	public static void deleteDirectory(String dir) throws IOException {
		File file = new File(dir);
		if (file.exists()) {
			deleteDirectory(file);
		}
	}
	
  public static boolean copyFiles(String sourceFile, String targtFile) {
    try {
      File sfile = new File(sourceFile);
      if (sfile.isFile()) {
        copyFileNew(sourceFile, targtFile);
      } else if (sfile.isDirectory()) {
        File[] fileList = sfile.listFiles();
        for (int i = 0; i < fileList.length; i++) {
          copyFiles(fileList[i].getPath(), targtFile + File.separator
              + fileList[i].getName());
        }
      } else {
        return false;
      }
    } catch (Exception e) {
      return false;
    }

    return true;
  }

  public static boolean copyFileNew(String sourceFile, String targtFile) {
    try {
      File sfile = new File(sourceFile);
      File tfile = new File(targtFile);
      File pfile = new File(tfile.getParent());
      if (!pfile.exists()) {
        pfile.mkdirs();
      }
      if (sfile.exists()) {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
          in = new FileInputStream(sfile);
          out = new FileOutputStream(tfile);

          byte[] buff = new byte[1024];
          int length = 0;
          while ((length = in.read(buff, 0, 1024)) > 0) {
            out.write(buff, 0, length);
          }

        } catch (Exception e) {
          log.error("拷贝文件出错：", e);
          return false;
        } finally {
          if (in != null) {
            in.close();
          }
          if (out != null) {
            out.flush();
            out.close();
          }
        }
      }
    } catch (Exception e) {
      return false;
    }
    return true;
  }
  /**
   * copy同时校验
   * @param sourceFile
   * @param targtFile
   * @return
   * author liyin 
   * create time 3:19:10 PM
   */
  public static boolean copyFileAndCheck(String sourceFile, String targtFile) {
  	boolean isOk = false ;
  	try {
  		File sfile = new File(sourceFile);
  		File tfile = new File(targtFile);
  		File pfile = new File(tfile.getParent());
  		if (!pfile.exists()) {
  			pfile.mkdirs();
  		}
  		if (sfile.exists()) {
  			FileInputStream in = null;
  			FileOutputStream out = null;
  			try {
  				in = new FileInputStream(sfile);
  				out = new FileOutputStream(tfile);
  				
  				byte[] buff = new byte[1024];
  				int length = 0;
  				while ((length = in.read(buff, 0, 1024)) > 0) {
  					out.write(buff, 0, length);
  				}
  				isOk = true ;
  			} catch (Exception e) {
  				log.error("拷贝文件出错：", e);
  				isOk = false ;
  			} finally {
  				if (in != null) {
  					in.close();
  				}
  				if (out != null) {
  					out.flush();
  					out.close();
  				}
  			}
  		}
  	} catch (Exception e) {
  		return isOk;
  	}
  	return isOk ;
  }

  /**
   * 
   * 功能描述：拷贝文件
   * 
   * @author 
   * @version 0.1
   * @date: Nov 1, 2007
   * 
   * @param sourceFile
   *            源文件
   * @param targtFile
   *            目标文件
   * @return 拷贝是否成功
   */
  public static boolean copyFile(String sourceFile, String targtFile) {
    try {
      File sfile = new File(sourceFile);
      File tfile = new File(targtFile);
      if (sfile.exists()) {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
          in = new FileInputStream(sfile);
          out = new FileOutputStream(tfile);

          byte[] buff = new byte[1024];
          int length = 0;
          while ((length = in.read(buff, 0, 1024)) > 0) {
            out.write(buff, 0, length);
          }

        } catch (Exception e) {
          log.error("拷贝文件出错：", e);
          return false;
        } finally {
          if (in != null) {
            in.close();
          }
          if (out != null) {
            out.flush();
            out.close();
          }
        }
      }
    } catch (Exception e) {
      return false;
    }
    return true;
  }

  /**
   * 
   * 功能描述：分离机考软件编制的cbt包为zip包
   * 
   * @author 
   * @version
   * @date: Nov 30, 2007
   * 
   * @param cbtPath
   *            cbt包路径
   * @param extractfilepath
   *            分离后要保存zip包
   * @throws Exception
   */
  public static void splitCbtFile(String cbtPath, String extractfilepath)
      throws Exception {
    FileInputStream in = null;
    FileOutputStream out = null;

    try {
      File file = new File(cbtPath);
      File ofile = new File(extractfilepath);
      in = new FileInputStream(file);
      out = new FileOutputStream(ofile);

      byte[] bf = new byte[4];
      in.read(bf, 0, bf.length);
      byte[] bf2 = new byte[1];
      bf2[0] = bf[0];
      int length = bytes2int(bf2);
      byte[] signbf = new byte[length];
      in.read(signbf, 0, signbf.length);

      byte[] zipbf = new byte[1024];
      while (in.read(zipbf, 0, zipbf.length) > 0) {
        out.write(zipbf, 0, zipbf.length);
      }
    } catch (Exception e) {
      throw new Exception(e);
    } finally {
      if (in != null) {
        in.close();
      }
      if (out != null) {
        out.flush();
        out.close();
      }
    }

  }

  /**
   * 
   * 功能描述：将byte数组转换为int
   * 
   * @author 
   * @version
   * @date: Nov 30, 2007
   * 
   * @param b
   * @return
   */
  public static int bytes2int(byte[] b) {
    int mask = 0xff;
    int temp = 0;
    int res = 0;
    for (int i = 0; i < b.length; i++) {
      res <<= 8;
      temp = b[i] & mask;
      res |= temp;
    }
    return res;
  }

  /**
   * 将int类型的数据转换为byte数组 原理：将int数据中的四个byte取出，分别存储
   * 
   * @param n
   *            int数据
   * @return 生成的byte数组
   */
  public static byte[] int2bytes(int n) {
    byte[] b = new byte[4];
    for (int i = 0; i < 4; i++) {
      b[3 - i] = (byte) (n >> (24 - i * 8));
    }
    return b;
  }

  /**
   * 
   * 功能描述：获取文件的MD5值
   * 
   * @author 
   * @date: Nov 29, 2008
   * @param fileName
   * @return base64后的值
   * @throws Exception
   */
  public static byte[] getFileMD5(String fileName) throws Exception {
    File file = new File(fileName);
    return getFileMD5(file);
  }

  /**
   * 
   * 功能描述：获取文件的MD5值
   * 
   * @author 
   * @date: Nov 30, 2008
   * @param file
   * @return base64后的值
   * @throws Exception
   */
  public static byte[] getFileMD5(File file) throws Exception {
    InputStream fis = null;
    byte[] md5Byte = null;
    try {
      fis = new FileInputStream(file);
      byte[] buffer = new byte[fis.available()];
      MessageDigest md5 = MessageDigest.getInstance("MD5");
      fis.read(buffer);
      fis.close();
      md5.update(buffer);
      md5Byte = md5.digest();
    } catch (RuntimeException e) {
      throw e;
    } finally {
      if (fis != null) {
        fis.close();
      }
    }
    return md5Byte;
  }

  /**
   * 
   * 功能描述：对byte数组进行MD5计算
   * 
   * @author 
   * @date: Nov 29, 2008
   * @param b
   * @return
   */
  public static byte[] md5Byte(byte[] b) {
    MessageDigest digest = null;
    try {
      digest = MessageDigest.getInstance("MD5");
      digest.update(b);
      return digest.digest();
    } catch (NoSuchAlgorithmException e) {
      return null;
    }
  }

  /**
   * 签名压缩包
   * 
   * @param filePath
   * @throws Exception
   */
  public static void sign(String filePath) throws Exception {
    FileInputStream fileInputStream = new FileInputStream(new File(filePath));
    byte[] buffer = new byte[fileInputStream.available()];
    fileInputStream.read(buffer);
    fileInputStream.close();
    byte[] encrypValue = md5Byte(buffer);
    byte[] lengthValue = int2bytes(encrypValue.length);
    OutputStream outputStream = new FileOutputStream(filePath);
    outputStream.write(lengthValue, 0, lengthValue.length); // md5长度
    outputStream.write(encrypValue, 0, encrypValue.length); // md5信息
    outputStream.write(buffer, 0, buffer.length); // 文件本身信息
    outputStream.close();
  }
  public static void main(String[] a) {
//    byte[] bt = null;
    try {
//      bt = getFileMD5("D:\\examfile\\wmp\\cbtpa\\tokenInfo\\TokenUser.zip");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}